package ysq.xyg.util;

import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ysq.xyg.model.BaseJob;

/**
 * Quartz任务管理工具类
 *
 * @author taocongcong
 * @create 2018-08-28 9:27
 */
public class SchedulerUtils {
    private static final Logger logger = LoggerFactory.getLogger(SchedulerUtils.class);

    @SuppressWarnings("unchecked")
    public static void createScheduleJob(BaseJob record, Scheduler scheduler) {
        // 加载job类
        String className = record.getClassName();
        try {
            if (StringUtils.isEmpty(className)) {
                logger.info("id:{}无对应类", record.getId());
            }
            Class aClass = Class.forName(record.getClassName());
            if (Job.class.isAssignableFrom(aClass)) {
                Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(className);
                String name = record.getJobName();
                String group = record.getJobGroup();
                // 生成jobDetail
                JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(name, group).build();
                // 表达式调度构建器
                CronScheduleBuilder cornSB = CronScheduleBuilder.cronSchedule(record.getCronExpression());
                // 生成触发器
                CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group).withSchedule(cornSB).build();
                // 添加job
                scheduler.scheduleJob(jobDetail, trigger);
                // 暂停任务
                if (record.getStatus().equals(BaseConstant.SchedulerStatus.PAUSE.getValue())) {
                    pauseJob(scheduler, record.getJobName(), record.getJobGroup());
                }
            } else {
                logger.info("类{}未继承Job接口", record.getClassName());
            }
        } catch (Exception e) {
            logger.info("类{}未找到", record.getClassName());
        }
    }

    /**
     * 获取触发器key
     */
    public static TriggerKey getTriggerKey(String jobName, String jobGroup) {

        return TriggerKey.triggerKey(jobName, jobGroup);
    }

    /**
     * 恢复任务执行
     *
     * @param scheduler 调度器
     * @param jobName   任务名
     * @param groupName 组织名
     */
    public static void resumeJob(Scheduler scheduler, String jobName, String groupName) {
        JobKey jobKey = new JobKey(jobName, groupName);
        try {
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            logger.info("定时任务恢复失败");
        }
    }

    /**
     * 获取表达式触发器
     *
     * @param scheduler the scheduler
     * @param jobName   the job name
     * @param jobGroup  the job group
     * @return cron trigger
     */
    public static CronTrigger getCronTrigger(Scheduler scheduler, String jobName, String jobGroup) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            return (CronTrigger) scheduler.getTrigger(triggerKey);
        } catch (SchedulerException e) {
            logger.error("获取定时任务CronTrigger出现异常", e);
        }
        return null;
    }

    /**
     * 暂停任务执行
     *
     * @param scheduler 调度器
     * @param jobName   任务名
     * @param groupName 组织名
     */
    public static void pauseJob(Scheduler scheduler, String jobName, String groupName) {
        JobKey jobKey = new JobKey(jobName, groupName);
        try {
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            logger.info("定时任务暂停失败");
            e.printStackTrace();
        }
    }

    /**
     * 运行一次
     *
     * @param scheduler 调度器
     * @param jobName   任务名
     * @param groupName 组织名
     */
    public static void runOne(Scheduler scheduler, String jobName, String groupName) {
        JobKey jobKey = new JobKey(jobName, groupName);
        try {
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            logger.info("运行一次失败");
        }
    }

    /**
     * 运行一次
     *
     * @param scheduler 调度器
     * @param sysJob   任务
     */
    public static void runOne(Scheduler scheduler, BaseJob sysJob) {
        JobKey jobKey = new JobKey(sysJob.getJobName(), sysJob.getJobGroup());
        try {
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            logger.info("运行一次失败");
        }
    }

    /**
     * 删除任务
     *
     * @param scheduler 调度器
     * @param jobName   任务名
     * @param groupName 组织名
     */
    public static void deleteJob(Scheduler scheduler, String jobName, String groupName) {
        JobKey jobKey = new JobKey(jobName, groupName);
        try {
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            logger.info("删除定时任务失败");
        }
    }

    /**
     * 更新定时任务
     *
     * @param scheduler the scheduler
     * @param record  the schedule job
     */
    public static void updateScheduleJob(Scheduler scheduler, BaseJob record) {
        try {
            TriggerKey triggerKey = getTriggerKey(record.getJobName(), record.getJobGroup());
            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(record.getCronExpression());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            //按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
            scheduler.rescheduleJob(triggerKey, trigger);
            // 忽略状态为PAUSED的任务，解决集群环境中在其他机器设置定时任务为PAUSED状态后，集群环境启动另一台主机时定时任务全被唤醒的bug
            /*if (!triggerState.name().equalsIgnoreCase("PAUSED")) {
                //按新的trigger重新设置job执行
                scheduler.rescheduleJob(triggerKey, trigger);
            }*/
            // 暂停任务
            if (record.getStatus().equals(BaseConstant.SchedulerStatus.PAUSE.getValue())) {
                pauseJob(scheduler, record.getJobName(), record.getJobGroup());
            }
        } catch (SchedulerException e) {
            logger.error("更新定时任务失败", e);
        }
    }
}
